<template>
  <!-- 修改模板中的容器样式 -->
  <div ref="container" id="container" 
       style="position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; z-index: 1; pointer-events: all;">

    <!-- 相机信息卡片 -->
    <van-cell-group class="control-panel">
      <van-cell title="相机信息">
        <template #value>
          <div class="camera-info">
            <div>X: {{ cameraPos.x }}</div>
            <div>Y: {{ cameraPos.y }}</div>
            <div>Z: {{ cameraPos.z }}</div>
          </div>
        </template>
      </van-cell>

      <!-- 控制按钮组 -->
      <van-cell title="模型控制">
        <template #value>
          <van-button
            size="mini"
            @click="resetCamera"
            icon="replay"
          >重置视角</van-button>
        </template>
      </van-cell>
    </van-cell-group>

    <!-- 右侧控制面板 -->
    <van-popup
      v-model:show="showControls"
      position="right"
      :style="{ width: '30%', height: '100%' }"
    >
      <van-cell-group title="点云控制">
        <van-cell title="点尺寸">
          <van-slider
            v-model="pointSize"
            :min="0.001"
            :max="0.01"
            :step="0.001"
            @change="updatePointSize"
          />
        </van-cell>

        <van-cell title="背景颜色">
          <input
              type="color"
              v-model="backgroundColor"
              @change="updateBackgroundColor"
              style="width: 30px; height: 30px"
          />
        </van-cell>

        <van-cell title="X轴旋转">
          <van-slider
            v-model="rotationX"
            :min="-180"
            :max="180"
            @change="updateRotationX"
          />
        </van-cell>

        <van-cell title="Y轴旋转">
          <van-slider
            v-model="rotationY"
            :min="-180"
            :max="180"
            @change="updateRotationY"
          />
        </van-cell>

        <van-cell title="X轴平移">
          <van-slider
            v-model="translateX"
            :min="-10"
            :max="10"
            :step="0.1"
            @change="updateTranslateX"
          />
        </van-cell>

        <van-cell title="缩放比例">
          <van-slider
            v-model="scaleFactor"
            :min="0.1"
            :max="10"
            :step="0.1"
            @change="updateScale"
          />
        </van-cell>

        <van-cell title="可见性">
          <van-switch v-model="modelVisible" @change="toggleVisibility"/>
        </van-cell>
      </van-cell-group>
    </van-popup>
  <div 
    v-if="showSidebar" 
    class="image-card"
    :style="{ 
      right: showSidebar ? '20px' : '-100%', 
      opacity: showSidebar ? 1 : 0 
    }"
  >
    <div class="card-header">
      <van-icon 
        name="cross" 
        class="close-btn" 
        @click="showSidebar = false"
      />
      <h3>标记点图片</h3>
    </div>
    
    <div class="card-content">
      <van-grid :column-num="2" gutter="8px">
        <van-grid-item 
          v-for="(image, index) in images" 
          :key="index"
        >
          <img 
            :src="image" 
            class="card-image" 
            alt="点位图片"
            @click="previewImage(image)"
          />
        </van-grid-item>
      </van-grid>
    </div>
  </div>
    <div class="float-button">
      <van-button
          round
          type="primary"
          @click="showControls = true"
          icon="setting-o"
      >控制</van-button>
      <div v-if="isSelecting" class="selection-box" :style="boxStyle"></div>
    </div>
  </div>
</template>

<script>
import { markRaw } from 'vue';
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { PCDLoader } from 'three/examples/jsm/loaders/PCDLoader.js';

export default {
  name: 'PointCloudViewer',
  data() {
    return {
      markers: [], // 存储标记点信息 { position: Vector3, id: number }
      raycaster: new THREE.Raycaster(),
      clickPosition: new THREE.Vector2(),
      isSelecting: false,
      selectionStart: { x: 0, y: 0 },
      selectionEnd: { x: 0, y: 0 },
      boxHelper: null,
      showControls: true,
      cameraPos: { x: 0, y: 0, z: 0 },
      pointSize: 0.005,
      scaleFactor: 1,
      modelVisible: true,
      rotationX: 0,
      rotationY: 0,
      loadingProgress: 0,
      translateX: 0,
      currentColor: '#FFFFFF',
      animationFrameId: null, // 新增动画帧ID
      backgroundColor: '#000000', // 黑色背景
       showSidebar: false, // 新增侧边栏显示控制变量
    images: [ // 新增图片数组
      'path/to/image1.jpg',
      'path/to/image2.jpg',
      'path/to/image3.jpg'
    ]
    };
  },
  created() {
    // 初始化 threeContext 对象
    this.threeContext = {
      scene: markRaw(new THREE.Scene()),
      camera: null,
      renderer: null,
      controls: null,
      currentPoints: null
    };
  },
  mounted() {
    this.initThree();
    window.addEventListener('resize', this.handleResize);
    this.initInteraction();
  },
  beforeUnmount() {
    if (this.threeContext.currentPoints) {
      this.threeContext.currentPoints.geometry.dispose();
      this.threeContext.currentPoints.material.dispose();
    }

    // 清理所有纹理
    this.threeContext.scene.traverse((obj) => {
      if (obj.material) {
        obj.material.dispose();
        if (obj.material.map) obj.material.map.dispose();
      }
      if (obj.geometry) obj.geometry.dispose();
    });

    // 移除事件监听器
    const dom = this.$refs.container;
    dom.removeEventListener('click', this.handleClick);
  },
  methods: {
    addMarker(position, id) {
      const marker = {
        id,
        position: position.clone(),
 sprite: markRaw(this.createMarkerSprite(id)) 
      };

      // 设置位置并添加到场景
  marker.sprite.position.copy(position);
  this.threeContext.scene.add(marker.sprite);
  this.markers.push(marker);

      // 调试信息
      console.log(`添加标记点 ${id}，位置：${position.x}, ${position.y}, ${position.z}`);
    },

    // 创建标记精灵
    createMarkerSprite(id) {
      const canvas = document.createElement('canvas');
      canvas.width = 64;
      canvas.height = 64;
      const ctx = canvas.getContext('2d');

      // 绘制标记图形
      ctx.beginPath();
      ctx.arc(32, 32, 24, 0, Math.PI * 2);
      ctx.fillStyle = '#ff4444';
      ctx.fill();
      ctx.strokeStyle = 'white';
      ctx.lineWidth = 3;
      ctx.stroke();
      ctx.fillStyle = 'white';
      ctx.font = 'bold 18px Arial';
      ctx.textAlign = 'center';
      ctx.fillText(id.toString(), 32, 38);

      const texture = new THREE.CanvasTexture(canvas);
      const material = new THREE.SpriteMaterial({
        map: texture,
        depthTest: true, // 开启深度测试
        transparent: true // 允许透明度
      });

      return new THREE.Sprite(material);
    },

    // 添加点击事件监听
    initInteraction() {
      const dom = this.$refs.container;
      
      // 移除旧事件监听器防止重复绑定
      dom.removeEventListener('click', this.handleClick);
      dom.addEventListener('click', this.handleClick.bind(this));
    },

    // 点击事件处理函数
    handleClick(event) {
      // 添加防御性检查
      if (!this.threeContext.camera || !this.threeContext.scene) {
        console.error('Three.js上下文未初始化');
        return;
      }

      // 精确计算点击坐标
      const rect = this.$refs.container.getBoundingClientRect();
      const x = event.clientX - rect.left;
      const y = event.clientY - rect.top;

      // 转换为标准化设备坐标 (NDC)
      this.clickPosition.x = (x / rect.width) * 2 - 1;
      this.clickPosition.y = - (y / rect.height) * 2 + 1;

      // 更新射线投射器
      this.raycaster.setFromCamera(this.clickPosition, this.threeContext.camera);

      // 优化检测对象收集
      const markerObjects = this.markers
        .filter(m => m.sprite)
        .map(m => m.sprite);

      // 执行检测
      const intersects = this.raycaster.intersectObjects(markerObjects, true);

      // 调试输出
      console.log('检测到的交点:', intersects);
      if (intersects.length > 0) {
        const marker = this.markers.find(
          m => m.sprite === intersects[0].object
        );
        console.log(`成功点击 ${marker.id} 号点位`);
        // 添加视觉反馈
        this.highlightMarker(marker);
         this.showSidebar = true;
      }
    },

    // 标记高亮方法
    highlightMarker(marker) {
      // 临时缩放效果
      marker.sprite.scale.set(1.2, 1.2, 1);
      setTimeout(() => {
        marker.sprite.scale.set(1, 1, 1);
      }, 200);
    },

    updateBackgroundColor() {
      if (this.threeContext.scene) {
        this.threeContext.scene.background = new THREE.Color(this.backgroundColor);
        this.animateRender();
      }
    },

    resetCamera() {
      if (this.threeContext.controls) {
        this.threeContext.controls.reset();
        this.threeContext.camera.position.set(29, -8, 1000.00);
        this.animateRender();
      }
    },

    updatePointSize(value) {
      if (this.threeContext.currentPoints?.material) {
        this.threeContext.currentPoints.material.size = value;
        this.animateRender();
      }
    },

    updateRotationX(value) {
      if (this.threeContext.currentPoints) {
        const radian = THREE.MathUtils.degToRad(value);
        const matrix = new THREE.Matrix4().makeRotationX(radian);

        const originalPos = this.threeContext.currentPoints.position.clone();

        this.threeContext.currentPoints.position.set(0, 0, 0);
        this.threeContext.currentPoints.position.applyMatrix4(matrix);

        this.threeContext.currentPoints.position.add(originalPos);

        this.animateRender();
      }
    },

    updateRotationY(value) {
      if (this.threeContext.currentPoints) {
        const radian = THREE.MathUtils.degToRad(value);
        const matrix = new THREE.Matrix4().makeRotationY(radian);

        // 创建临时向量存储原始位置
        const originalPos = this.threeContext.currentPoints.position.clone();

        // 先重置位置再应用旋转
        this.threeContext.currentPoints.position.set(0, 0, 0);
        this.threeContext.currentPoints.position.applyMatrix4(matrix);

        // 恢复原始位置基础上应用旋转
        this.threeContext.currentPoints.position.add(originalPos);

        this.animateRender();
      }
    },

    updateTranslateX(value) {
      if (this.threeContext.currentPoints) {
        // 计算相对于上一帧的位移差
        const moveDistance = value - this.translateX;
        const moveX = moveDistance * Math.cos(this.threeContext.currentPoints.rotation.y);
        const moveZ = moveDistance * Math.sin(this.threeContext.currentPoints.rotation.y);
        
        // 应用位移（Y轴保持原值）
        this.threeContext.currentPoints.position.x += moveX;
        this.threeContext.currentPoints.position.z += moveZ;
        this.translateX = value;

        this.animateRender();
      }
    },

    updateScale(value) {
      if (this.threeContext.currentPoints) {
        this.threeContext.currentPoints.scale.set(value, value, value);
        this.animateRender();
      }
    },

    toggleVisibility(visible) {
      if (this.threeContext.currentPoints) {
        this.threeContext.currentPoints.visible = visible;
        this.animateRender();
      }
    },

    initThree() {
      // 清理旧实例
      if (this.animationFrameId) {
        cancelAnimationFrame(this.animationFrameId);
      }

      // 初始化场景
      this.threeContext.scene.background = new THREE.Color(this.backgroundColor);

      // 初始化渲染器
      this.threeContext.renderer = markRaw(new THREE.WebGLRenderer({
        antialias: true,
        powerPreference: 'high-performance',
        logarithmicDepthBuffer: false // 关闭对数缓冲
      }));
      this.threeContext.renderer.setSize(window.innerWidth, window.innerHeight);
      this.$refs.container.appendChild(this.threeContext.renderer.domElement);
      this.threeContext.renderer.autoClear = false;
      this.threeContext.renderer.sortObjects = false;

      // 初始化相机
      this.threeContext.camera = markRaw(new THREE.PerspectiveCamera(
        45,
        window.innerWidth / window.innerHeight,
        0.01,  // 减小近平面
        10000  // 增大远平面
      ));
      this.threeContext.camera.position.set(29, -8, 1000.00);

      // 初始化控制器（添加空值校验）
      if (this.threeContext.camera && this.threeContext.renderer) {
        this.threeContext.controls = markRaw(new OrbitControls(
          this.threeContext.camera,
          this.threeContext.renderer.domElement
        ));
        this.threeContext.controls.target.set(0, 0, 0);

        // 添加初始视角调整
        this.threeContext.controls.update();
        this.animateRender(); // 强制渲染一次
        this.setupControls();
      }

      // 加载点云
      this.loadPointCloud();

      // 启动受控的动画循环
      this.startAnimation();
    },

    setupControls() {
      if (!this.threeContext.controls) return;
      this.threeContext.controls.enableRotate = true; // 确保旋转启用
      this.threeContext.controls.enableZoom = true;   // 确保缩放启用
      this.threeContext.controls.enablePan = true;    // 确保平移启用
      this.threeContext.controls.dampingFactor = 0.09;
      this.threeContext.controls.enableDamping = true; // 关闭阻尼提升响应
      this.threeContext.controls.rotateSpeed = 0.8;      // 降低操作灵敏度
      this.threeContext.controls.panSpeed = 1.0;
      this.threeContext.controls.zoomSpeed = 5.2;
      this.threeContext.controls.screenSpacePanning = true;
      this.threeContext.controls.target.set(0, 0.1, 0);
      this.threeContext.controls.minDistance = 0;
      this.threeContext.controls.maxDistance = 1000;
      this.threeContext.controls.minPolarAngle = 0; // 默认值0（允许向下看）
      this.threeContext.controls.maxPolarAngle = Math.PI;
    },

    downsampleGeometry(geometry, ratio) {
      const count = geometry.attributes.position.count;
      const newCount = Math.floor(count * ratio);
      const newGeometry = new THREE.BufferGeometry();

      const indices = new Array(count).fill().map((_, i) => i);
      indices.sort(() => Math.random() - 0.5);

      const selected = indices.slice(0, newCount);

      const positions = new Float32Array(newCount * 3);
      const colors = new Float32Array(newCount * 3);

      selected.forEach((idx, i) => {
        positions[i * 3] = geometry.attributes.position.array[idx * 3];
        positions[i * 3 + 1] = geometry.attributes.position.array[idx * 3 + 1];
        positions[i * 3 + 2] = geometry.attributes.position.array[idx * 3 + 2];

        if (geometry.attributes.color) {
          colors[i * 3] = geometry.attributes.color.array[idx * 3];
          colors[i * 3 + 1] = geometry.attributes.color.array[idx * 3 + 1];
          colors[i * 3 + 2] = geometry.attributes.color.array[idx * 3 + 2];
        }
      });

      newGeometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
      if (geometry.attributes.color) {
        newGeometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));
      }

      return newGeometry;
    },

    loadPointCloud() {
      const loader = new PCDLoader();
      loader.load('models/kaihua_bridge_scans.pcd',
        (points) => {
          // 创建新点云对象而不是冻结对象
          const simplifiedGeometry = this.downsampleGeometry(points.geometry, 0.5);
          const positions = simplifiedGeometry.attributes.position.array;

          // 计算Z轴范围
          let minZ = Infinity, maxZ = -Infinity;
          for (let i = 2; i < positions.length; i += 3) {
            const z = positions[i];
            minZ = Math.min(minZ, z);
            maxZ = Math.max(maxZ, z);
          }
          const rangeZ = maxZ - minZ;

          // 创建颜色数组（蓝->青->黄->红渐变）
          const colors = new Float32Array(positions.length);
          for (let i = 0; i < positions.length; i += 3) {
            const z = positions[i + 2];
            const ratio = (z - minZ) / rangeZ;

            // 五段式渐变算法
            const color = new THREE.Color();
            if (ratio <= 0.25) {
              // 深蓝 -> 蓝 (B: 0.6 -> 1.0)
              color.r = 0;
              color.g = 0;
              color.b = 0.6 + (ratio * 0.4); // 从0.6到1.0
            } else if (ratio < 0.5) {
              // 蓝 -> 青 (B->G)
              const t = (ratio - 0.25) / 0.25;
              color.r = 0;
              color.g = t;
              color.b = 1 - (t * 0.4); // 从1.0到0.6
            } else if (ratio < 0.75) {
              // 青 -> 绿 (G)
              const t = (ratio - 0.5) / 0.25;
              color.r = t;
              color.g = 1;
              color.b = 1 - t;
            } else if (ratio < 1.0) {
              // 绿 -> 黄 (G->R)
              const t = (ratio - 0.75) / 0.25;
              color.r = 1;
              color.g = 1 - t;
              color.b = 0;
            } else {
              // 黄 -> 红 (R)
              color.r = 1;
              color.g = 0;
              color.b = 0;
            }
            colors[i] = color.r;
            colors[i + 1] = color.g;
            colors[i + 2] = color.b;
          }

          simplifiedGeometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));
          const processedPoints = new THREE.Points(
            simplifiedGeometry,
            new THREE.PointsMaterial({
              precision: 'highp',
              size: this.pointSize,
              vertexColors: true,
              sizeAttenuation: true,
              alphaTest: 0,        // 这个值过高会导致很多点被裁剪
              transparent: false,  // 关闭透明度处理
              depthTest: true      // 开启深度测试
            })
          );

          // 设置旋转
          processedPoints.rotation.set(Math.PI / 2, Math.PI, 0); // 调整为横置
          processedPoints.name = 'Zaghetto.pcd';

          this.threeContext.scene.add(processedPoints);
          this.threeContext.currentPoints = processedPoints;

          // 在加载完成后添加示例标记
          const bbox = new THREE.Box3().setFromObject(processedPoints);
          const center = bbox.getCenter(new THREE.Vector3());
          this.$nextTick(() => {
            this.addMarker(center, 1);
            this.addMarker(center.clone().add(new THREE.Vector3(2, 15, 20)), 2);
          });
        },
        undefined,
        (error) => {
          console.error('点云加载失败:', error);
        }
      );
    },

    // 修改startAnimation方法
    startAnimation() {
      let lastRender = 0;
      const renderInterval = 1000 / 30; // 保持30fps限制

      const animate = (timestamp) => {
        this.animationFrameId = requestAnimationFrame(animate);

        // 限制渲染频率
        if (timestamp - lastRender < renderInterval) return;
        lastRender = timestamp;

        // 强制更新控制器
        if (this.threeContext.controls) {
          this.threeContext.controls.update(); // 必须始终调用update()
        }

        this.animateRender(); // 必须持续渲染
      };

      animate();
    },

    stopAnimation() {
      if (this.animationFrameId) {
        cancelAnimationFrame(this.animationFrameId);
        this.animationFrameId = null;
      }
    },

    updateCameraPosition() {
      if (this.threeContext.camera) {
        this.cameraPos = {
          x: this.threeContext.camera.position.x.toFixed(2),
          y: this.threeContext.camera.position.y.toFixed(2),
          z: this.threeContext.camera.position.z.toFixed(2)
        };
        this.$forceUpdate();
      }
    },

    animateRender() {
      if (this.threeContext.renderer && this.threeContext.scene && this.threeContext.camera) {
        this.threeContext.renderer.render(
          this.threeContext.scene,
          this.threeContext.camera
        );
        this.updateCameraPosition();
      }
    },

    handleResize() {
      if (this.threeContext.camera && this.threeContext.renderer) {
        this.threeContext.camera.aspect = window.innerWidth / window.innerHeight;
        this.threeContext.camera.updateProjectionMatrix();
        this.threeContext.renderer.setSize(window.innerWidth, window.innerHeight);
        this.animateRender();
      }
    }
  }
};
</script>

<style scoped>
#container {
  width: 100%;
  height: 100%;
  margin: 0;
  overflow: hidden;
  pointer-events: all;
  z-index: 1;
}

.control-panel {
  z-index: 1000;
  pointer-events: none;
  position: absolute;
  top: 20px;
  left: 20px;
  width: 260px;
  background: rgba(255, 255, 255, 0.9);
  border-radius: 8px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}

.control-panel * {
  pointer-events: auto;
}

.float-button {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 1001;
  pointer-events: auto;
}

.van-cell__value {
  text-align: left !important;
  margin-top: 3% !important; /* 覆盖Vant默认右对齐 */
}

.van-cell__value >>> div {
  text-align: left !important;
  margin-top: 3% !important;
}

.van-popup {
  background: rgba(255, 255, 255, 0.95) !important;
  backdrop-filter: blur(5px);
}

.van-cell__title {
  font-weight: 500;
  color: #2c3e50;
}
.image-card {
  position: fixed;
  top: 20px;
  right: 20px;
  width: 320px;
  height: 93vh;
  max-height: 80vh;
  background: rgba(255, 255, 255, 0.95);
  border-radius: 12px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  transition: all 0.3s ease;
  z-index: 999;
}

.card-header {
  display: flex;
  align-items: center;
  padding: 12px;
  border-bottom: 1px solid #eee;
  position: relative;
}

.close-btn {
  position: absolute;
  right: 12px;
  font-size: 18px;
  color: #969799;
}

.card-content {
  padding: 12px;
  overflow-y: auto;
  max-height: calc(80vh - 60px);
}

.card-image {
  width: 100%;
  height: 120px;
  object-fit: cover;
  border-radius: 6px;
  transition: transform 0.2s;
}

.card-image:hover {
  transform: scale(1.03);
  cursor: pointer;
}
</style>
